package com.atzly.community.utils;

import com.atzly.community.entity.User;
import org.springframework.stereotype.Component;

/**
 *  需求: 每条线程都需要存取一个同名变量，但每条线程中该变量的值均不相同
 * 用于保存登录的User对象,代替了session
 * ThreadLocal<User> 每个线程中都保存一个自己的user对象,通过key-value进行查找,
 * 这里的key代表线程,value代表User对象,这样做的好处比使用Map<Thread.currentThread(),User> 的方法要快很多
 * 原因是:后者在高并发的情况下必须使用synchronized锁的方式阻塞了线程
 * 实现原理:  首先ThreadLocal<> 在底层维护一个ThreadLocalMap.Entry对象
 * Entry(ThreadLocal<?> k, Object v) extend weakReference<ThreadLocal> {
 *         super(k);
 *         value = v;
 *     }
 * 简要说明: 这里的key代表了当前线程是唯一的成员变量 threadLocals,value表示当前User对象
 * Entry对象继承了weakReference 弱引用 key就是弱引用,表示如果没有强引用指向这个key,那么这个key在gc时会被回收
 *
 * 核心方法: set() get() remove()
 * 为什么要使用弱引用?  因为在java中为了方便程序员方便处理指针引用的问题
 *                    比如当创建过多对象object = new Object() 需要设置object = null 此时才会被gc回收
 *                    如果这里使用WeakReference弱引用的方式就无需手动释放了但是此时出现内存泄漏问题
 * WeakReference内存泄漏问题的解决方案:
 *                     问题来源: 如果value强引用一直不释放就会导致key-value的关系一直为强引用关系,gc并不会清理不使用的key从而导致内存泄漏问题
 *                     解决方案: 将一个大对象放入LocalThreadMap后便不再调用set、get、remove方法，此时该仍然可能会导致内存泄漏,此时就需要我们手动调用remove方法进行释放
 * 经典使用场景: web中的session存储
 * 使用spring的Interceptor进行Session对象的处理(提示需要手动调用remove方法)
 * @author zlysimida
 * @date 2021/8/27 - 13:37
 */
@Component
public class HostHolder {

    private ThreadLocal<User> threadLocal = new ThreadLocal<>();

    public void saveUserToThread(User user){
        threadLocal.set(user);
    }

    public User getUserFromThread(){
        return threadLocal.get();
    }

    public void removeUserFromThread(){
        threadLocal.remove();
    }
}
